
#include "zen_vap_sprite.h"
#include "zen_vap_helper.h"
#include "zen_vap_helper.h"

namespace Zen { namespace Vap {

	Sprite::Sprite()
	: Node2d(), PartWithMatrix2d(true)
	{
		initR_();
		this->setTextureScale(s_default_texture_scale);
	}
	
	/// content size {
	void Sprite::enableFixedSize(bool v)
	{
		if(m_is_fixed_sized == v) return;

		m_is_fixed_sized = v;

		if(m_is_fixed_sized)
		{
			this->setScale2_(m_fixed_size.w, m_fixed_size.h);
		}
		else if(!m_is_texture_dirty)
		{
			this->setScale2_(m_texture_size.w, m_texture_size.h);
		}
	}
	
	void Sprite::setFixedSize(Size2 size)
	{
		m_fixed_size = size;
		if(m_is_fixed_sized)
		{
			this->setScale2_(m_fixed_size.w, m_fixed_size.h);
		}
	}
	
	Size2 Sprite::getContentSize()
	{
		if(m_is_fixed_sized)
		{
			return m_fixed_size;
		}
		else
		{
			this->updateContent();
			return m_texture_size;
		}
	}
	/// } content size
	void Sprite::updateContent()
	{
		bool texture_dirty = this->updateTexture_();

		if(texture_dirty && !m_is_fixed_sized)
		{
			this->setScale2_(m_texture_size.w, m_texture_size.h);
		}
		if(texture_dirty || m_is_flip_dirty)
		{
			
			float x0 = m_texture_rect.x * m_texture->using_range().x;
			float y0 = m_texture_rect.y * m_texture->using_range().y;
			float x1 = m_texture_rect.w * m_texture->using_range().x + x0;
			float y1 = m_texture_rect.h * m_texture->using_range().y + y0;
			if(m_is_flip_x) std::swap(x0, x1);
			if(m_is_flip_y) std::swap(y0, y1);
			m_texture_rect_converted = { x0, y0, x1-x0, y1-y0 };
			
			m_is_flip_dirty = false;
		}
	}

	DrawBufferTexture & Sprite::getBuffer() {
		static DrawBufferTexture buffer;
		return buffer;
	}
	void Sprite::draw()
	{
		this->updateContent();

		this->updateMatrix();

		this->drawR_();
	}
#if ZEN_DRAW_GLES

	void Sprite::initR_()
	{
		if(getBuffer().v.count()) return;

		VertexDataTexture s_coords[] = {
			{ { 0, 0 }, { 0, 1 } },
			{ { 1, 0 }, { 1, 1 } },
			{ { 0, 1 }, { 0, 0 } },
			{ { 1, 1 }, { 1, 0 } },
		};
		getBuffer().v.updateBuffer(s_coords, 4);
	}
	void Sprite::drawR_()
	{

		if(!m_texture) return;

		auto alpha = DrawStack::Get()->getTopAlpha() * this->getAlpha();

		auto fmt = m_texture?m_texture->format() : ePixel::None;

		auto kit = m_shaders? m_shaders(fmt) : ShaderKitTexture::SelectorNormal()(fmt);

		Helper::Get()->performBlend(m_blend);

		kit->active();

		getBuffer().v.bind();

		using Type = decltype(getBuffer().v)::VertexData;
		kit->bindAttCoord(2, GL::eType::Float, 0, sizeof(Type), Type::OffCoord);
		kit->bindAttTexCoord(2, GL::eType::Float, 0, sizeof(Type), Type::OffTexCoord);

		kit->setUniMat4(this->getMatrix());
		kit->setUniColor(Vec4{ m_color.red, m_color.green, m_color.blue, m_color.alpha*alpha });
		kit->setUniTexRect(m_texture_rect_converted);
		if(m_texture) kit->setUniSampler(1, m_texture->buffer().getID());

		kit->prepare();
		kit->render(eVMode::TriangleStrip, 0, 4);
	}
	
#elif ZEN_DRAW_METAL
	void Sprite::initR_()
	{
	}
	void Sprite::drawR_()
	{
		if(getBuffer().is_dirty)
		{
			getBuffer().is_dirty = false;
			float x0 = m_texture_rect.x * m_texture->using_range().w;
			float y0 = m_texture_rect.y * m_texture->using_range().h;
			float x1 = m_texture_rect.w * m_texture->using_range().w + x0;
			float y1 = m_texture_rect.h * m_texture->using_range().w + y0;
			if(m_is_flip_x) std::swap(x0, x1);
			if(m_is_flip_y) std::swap(y0, y1);
			
			getBuffer().setVBufferRect4(x0, y0, x1, y1);
		}
		
		getBuffer().u.updateMatrix(this->getMatrix(), getMatrixVersion(), false);
		
		float alpha = DrawStack::Get()->getTopAlpha() * this->getAlpha();
		getBuffer().u.updateColor(getColor(), alpha, m_is_color_dirty);
		m_is_color_dirty = false;

		auto blends = Helper::Get()->getBlends(m_blend);
		
		auto pipe = Metal::ShaderKitTexture::GetShared(m_is_grey_mode, m_texture->format(), blends);
		
		kit->render(getBuffer().u, getBuffer().v, m_texture->buffer(), Metal::eVMode::TriangleStrip);
	}
#endif
}}

